home *** CD-ROM | disk | FTP | other *** search
-
- /*
-
- Program: Idle Led
- Version: 2.1a 1/3/94
- Author: Lindsay Meek (meek@fizzy.csu.murdoch.edu.au)
-
- Description: Whenever the CPU is busy, the power led goes on else it is off.
-
- This is the second version that operates by attaching itself
- to the vertical blanking interrupt. A low priority (-127)
- task is active which increments a counter and turns off the
- light. When this task does not run, the vblank irq detects
- the non-incrementing counter and turns the light on.
-
- This version is more system friendly than 1.0
-
- The CPU must be busy for more than 1 vbi for the
- light to activate
- */
-
- #include <exec/nodes.h>
- #include <exec/tasks.h>
- #include <exec/interrupts.h>
- #include <hardware/cia.h>
- #include <hardware/custom.h>
- #include <hardware/intbits.h>
- #include <libraries/dos.h>
-
- /* Assembly stub */
- extern void IdleIrq(void);
- extern void LightState(UWORD state);
-
- /* A string print (no formatting) that doesn't use as much memory as printf */
- void zprint(char *string)
- {
- extern BPTR Output(void);
- extern long Write(BPTR file, char *buffer, long length);
-
- Write(Output(),string,strlen(string));
-
- exit(1);
- }
-
- static UWORD idlelight_flag; /* Flag saying to turn the light on or off */
-
- /* Make the light 'active' depending on the idle flag */
- void LightActive(void)
- {
- LightState(idlelight_flag);
- }
-
- /* Make the light 'inactive' depending on the idle flag */
- void LightInactive(void)
- {
- LightState(!idlelight_flag);
- }
-
- /* System structure names */
- #define UTILITY_NAME "Idle_LED"
-
- /* various counters used to detect the idle state in the vblank */
- static ULONG idle_vbi_cnt_limit[3];
-
- /* Run this as a process. It aborts when it detects a CTRL_C signal */
- main(int argc,char **argv)
- {
- extern struct Task *FindTask(char *);
- struct Task *met;
- struct Interrupt mei;
- UWORD threshold;
- WORD oldpri;
- char *oldname;
- int i,kill_flag;
-
- threshold=50; /* Default: CPU threshold: > 50 % */
- idlelight_flag=1; /* Default: Make light come on for a busy cpu */
- kill_flag=0; /* Don't kill it */
-
- for(i=1;i<argc;i++)
- {
- if(!stricmp(argv[i],"off")) kill_flag=1; /* disable */
- else
- if(!stricmp(argv[i],"dim")) idlelight_flag=0; /* dim = busy */
- else
- if(!stricmp(argv[i],"threshold"))
- {
- if(++i > argc)
- zprint("Missing argument");
-
- threshold=atoi(argv[i]);
-
- /* clip threshold to stop silly buggers */
- if(threshold < 1) threshold=1;
- if(threshold > 99) threshold=99;
- }
- else
- if(stricmp(argv[i],"on") && stricmp(argv[i],"bright"))
- {
- zprint("Usage: Idle_LED {ON} {OFF} {BRIGHT} {DIM} {THRESHOLD n}\n");
- }
- }
-
- met=FindTask(UTILITY_NAME);
-
- if(kill_flag)
- {
- if(met==NULL)
- zprint("Idle_LED not running!\n");
-
- /* Send CTRL-C signal to task */
- Signal(met,SIGBREAKF_CTRL_C);
-
- zprint("Idle_LED terminating\n");
- }
-
- if(met!=NULL)
- zprint("Idle_LED already running!\n");
-
- mei.is_Node.ln_Type = NT_INTERRUPT;
- mei.is_Node.ln_Pri = -127;
- mei.is_Node.ln_Name = UTILITY_NAME;
- mei.is_Data = (APTR)idle_vbi_cnt_limit;
- mei.is_Code = IdleIrq;
-
- /* reset counter,last state */
-
- AddIntServer(INTB_VERTB, &mei); /* Install IRQ server */
-
- met=FindTask(NULL); /* Fetch this tcb */
- oldpri=met->tc_Node.ln_Pri; /* Save old priority */
- oldname=met->tc_Node.ln_Name; /* Save old name */
- met->tc_Node.ln_Name=UTILITY_NAME; /* Redirect task name */
- met->tc_Node.ln_Pri=40; /* Raise priority for calibration */
-
- idle_vbi_cnt_limit[0]=0;
- idle_vbi_cnt_limit[1]=0;
- idle_vbi_cnt_limit[2]=0;
-
- /* wait for next vbi */
- while(idle_vbi_cnt_limit[0]==0) ;
-
- /* count # of increments in one frame (for calibration) */
- idle_vbi_cnt_limit[2]=0;
- idle_vbi_cnt_limit[0]=0;
- while(idle_vbi_cnt_limit[0] == 0)
- idle_vbi_cnt_limit[2]++;
-
- /* > threshold % load is busy */
- idle_vbi_cnt_limit[2] = (idle_vbi_cnt_limit[2] * threshold)/100;
-
- met->tc_Node.ln_Pri=-127; /* Make priority VERY low for idle */
-
- /* Busy loop for eating idle cpu cycles */
- while((met->tc_SigRecvd & SIGBREAKF_CTRL_C)==0) /* Abort on CTRL_C */
- {
- /* Increment idle counter */
- idle_vbi_cnt_limit[1]++;
- }
-
- RemIntServer(INTB_VERTB,&mei); /* Remove IRQ server */
-
- met->tc_Node.ln_Pri=oldpri; /* Change priority back */
- met->tc_Node.ln_Name=oldname; /* Change name back */
-
- /* Turn on power led */
- LightState(1);
-
- return 0;
- }
-
- #asm
-
- ;
- ;Assembly section for vertical blanking interrupt server
- ;
- ;You may have to put this into a seperate .asm file and compile to get it working
- ;with your C compiler
- ;
-
- include "hardware/cia.i"
-
- _ciaa = $bfe001 ;i defined it here so i could use the small model!
-
- public _IdleIrq
- public _LightActive
- public _LightInactive
- public _LightState
-
- public _geta4
-
- _IdleIrq:
-
- move.l a4,-(sp) ;save a4
- jsr _geta4 ;retrieve a4 for global variables
-
- addq.l #1,(a1)+
-
- move.l (a1),d0 ;idle_cnt
- clr.l (a1)+ ;=0
- cmp.l (a1),d0 ;>=idle_limit
- bge.s _IdleIrq1 ;yes - then its idle
-
- jsr _LightActive ;turn on light - cpu is busy
-
- move.l (sp)+,a4
-
- moveq #0,d0 ;permit other servers to execute
- rts
-
- _IdleIrq1:
-
- jsr _LightInactive ;turn off light - cpu is idle
-
- move.l (sp)+,a4
-
- moveq #0,d0 ;permit other servers to execute
- rts
-
- ;
- ;void LightState(UWORD state)
- ;
- ;
- ;The routine is coded in assembly to prevent the C compiler from
- ;splitting up the read-modify-write cycle (bad news for hardware)
- ;
- _LightState:
-
- tst.w 4(sp) ;check state
- beq.s ls1 ;off?
- bclr.b #CIAB_LED,_ciaa+ciapra ;turn on power light (cpu is busy)
- rts
-
- ls1: bset.b #CIAB_LED,_ciaa+ciapra ;turn off power light (cpu is idle)
- rts
-
- #endasm
-